<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  <script src="wct-browser-config.js"></script>
  <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>
  <script type="module">
import { dedupingMixin } from '../../lib/utils/mixin.js';
suite('Mixin Utilities', () => {
  suite('Mixin Caching', () => {
    let mixinFn;
    let cachingMixinFn;
    suiteSetup(() => {
      mixinFn = (base) => class mixin extends base {
        mixed(){ return true; }
      };
      cachingMixinFn = dedupingMixin(mixinFn);
    });
    test('cachingMixin applies mixins', () => {
      let app = cachingMixinFn(class {});
      let inst = new app();
      assert.isFunction(inst.mixed);
      assert.equal(inst.mixed(), true);
    });
    test('Mixins are cached when the base class is identical', () => {
      class base {}
      let applicationOne = cachingMixinFn(base);
      let applicationTwo = cachingMixinFn(base);
      assert.equal(applicationOne, applicationTwo);
    });
    test('Original Mixin function keeps the cache', () => {
      assert.ok(mixinFn.__mixinApplications);
      assert.instanceOf(mixinFn.__mixinApplications, WeakMap);
      assert.notOk(cachingMixinFn.__mixinApplications);
    });
  });
  suite('Mixin Deduplicating', () => {
    let mixinFn, dedupingMixinFn;
    suiteSetup(() => {
      mixinFn = (base) => class mixin extends base {
        mixed(){ return true; }
      };
      dedupingMixinFn = dedupingMixin(mixinFn);
    });
    test('dedupingMixin applies mixins', () => {
      let app = dedupingMixinFn(class {});
      let inst = new app();
      assert.isFunction(inst.mixed);
      assert.equal(inst.mixed(), true);
    });
    test('dedupingMixin also caches', () => {
      class base {}
      let appOne = dedupingMixinFn(base);
      let appTwo = dedupingMixinFn(base);
      assert.equal(appOne, appTwo);
    });
    test('Mixins apply only if unique on the base class', () => {
      class base {}
      let appOne = dedupingMixinFn(base);
      class intermediate extends appOne {}
      let appTwo = dedupingMixinFn(intermediate);
      assert.equal(intermediate, appTwo);
      let inst = new appTwo();
      assert.equal(inst.mixed(), true);
    });
    test('Multiple deduplicating mixins apply uniquely', () => {
      let mixinFn1 = dedupingMixin((base) => class one extends base {
        one(){ return true; }
      });
      let mixinFn2 = dedupingMixin((base) => class two extends base {
        two(){ return true; }
      });
      class base {}
      let app1 = mixinFn1(base);
      let app2 = mixinFn2(app1);
      let app3 = mixinFn1(app2);
      assert.equal(app3, app2);
      let inst = new app3();
      assert.equal(inst.one(), true);
      assert.equal(inst.two(), true);
    });
    test('Classes with mixins do not share mixin sets', () => {
      let mixinFn1 = dedupingMixin((base) => class one extends base {
        one(){ return true; }
      });
      let mixinFn2 = dedupingMixin((base) => class two extends base {
        two(){ return true; }
      });
      let mixinFn3 = dedupingMixin((base) => class three extends base {
        three(){ return true; }
      });
      class base {}
      let app1 = mixinFn1(base);
      let app2 = mixinFn2(app1);
      let app3 = mixinFn3(app2);
      let appNot2 = mixinFn3(app1);
      assert.notEqual(appNot2.__mixinSet, app3.__mixinSet);
      let inst = new appNot2();
      assert.isFunction(inst.one);
      assert.isFunction(inst.three);
      assert.isNotFunction(inst.two);
    });
  });
});
</script>
</body>
</html>